package com.bridgeintelligent.tag.scene.service;

import com.bridgeintelligent.tag.scene.api.ISceneService;
import com.bridgeintelligent.tag.scene.api.dto.SceneDto;
import com.bridgeintelligent.tag.scene.api.dto.ScenePage;
import com.bridgeintelligent.tag.scene.api.entity.Scene;
import com.bridgeintelligent.tag.scene.api.entity.SceneCatalog;
import com.bridgeintelligent.tag.scene.api.entity.SceneStep;
import com.bridgeintelligent.tag.scene.api.model.SceneModel;
import com.bridgeintelligent.tag.scene.api.model.SceneMoveModel;
import com.bridgeintelligent.tag.scene.api.model.SceneQueryModel;
import com.bridgeintelligent.tag.scene.api.vo.*;
import com.bridgeintelligent.tag.scene.mapper.SceneCatalogMapper;
import com.bridgeintelligent.tag.scene.mapper.SceneMapper;
import com.bridgeintelligent.tag.user.mgmt.pojo.User;
import com.bridgeintelligent.tag.webserver.dim.mgmt.api.IdWorker;
import com.bridgeintelligent.tag.webserver.security.TagSecurityHelper;
import com.github.pagehelper.Page;
import com.github.pagehelper.PageHelper;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @description
 * @author: grp 2021-01-10 21:47
 **/
@AllArgsConstructor
@Service
@Slf4j
public class SceneServiceImpl implements ISceneService {

    private SceneCatalogMapper sceneCatalogMapper;
    private SceneMapper sceneMapper;
    @Override
    public List<String> inCatalogList(String sceneName) {
        return sceneCatalogMapper.inCatalogList(sceneName);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public SceneDto<Object> update(Scene scene) {
        if (StringUtils.isEmpty(scene.getCatalogId())) {
            return SceneDto.error("请选择标签目录！");
        }
        sceneMapper.updateCatalogIdById(scene.getId(), scene.getCatalogId(), new Date());
        return SceneDto.success();
    }

    @Override
    public List<Scene> findByCatalogId(String id) {
        List<Scene> scenes = new ArrayList<>(sceneMapper.findByCatalogId(id));
        List<SceneCatalog> catalogs = sceneCatalogMapper.findNext(id);
        List<String> nextCataIds = catalogs.stream()
                .map(SceneCatalog::getId)
                .collect(Collectors.toList());
        nextCataIds.forEach(cid -> {
            scenes.addAll(sceneMapper.findByCatalogId(cid));
        });
        return scenes;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void add(SceneModel model) {
        Scene base = model.getBase();
        Date date = new Date();
        base.setUpdateTime(date).setCreateTime(date).setId(IdWorker.nextId());
        User user = TagSecurityHelper.currentUser();
        base.setCreatorId(user.getUserId());
        sceneMapper.add(base);
        if(!CollectionUtils.isEmpty(model.getSteps())){
            List<SceneStep> steps = model.getSteps();
            steps.forEach(step->step.setId(IdWorker.nextId()).setSceneId(base.getId()));
            steps.forEach(sceneMapper::addSingleStep);
        }
        if(base.getTop()==1){
            Integer top = Integer.MAX_VALUE;
            List<Scene> scenes = sceneMapper.findBySort(top);
            if(CollectionUtils.isNotEmpty(scenes)){
                scenes.forEach(scene -> {
                    sceneMapper.unTop(scene.getId());
                });
            }
            sceneMapper.top(base.getId(), top);
        }
    }

    @Override
    public List<CustomersVO> findCustomers() {
        return sceneMapper.findCustomers();
    }

    @Override
    public List<CombinationTagVO> findCombinations() {
        User user = TagSecurityHelper.currentUser();
        return sceneMapper.findCombinations(user.getUserId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void put(SceneModel model) {
        Scene oldInfo = sceneMapper.findOneScene(model.getBase().getId());
        Scene base = model.getBase().setUpdateTime(new Date());
        sceneMapper.updateById(base);
        if(!CollectionUtils.isEmpty(model.getSteps())){
            sceneMapper.deleteStepsBySceneId(base.getId());
            List<SceneStep> steps = model.getSteps();
            steps.forEach(step->step.setId(IdWorker.nextId()).setSceneId(base.getId()));
            steps.forEach(sceneMapper::addSingleStep);
        }
        if(oldInfo.getTop()==1&&base.getTop()==0){
            sceneMapper.unTop(base.getId());
        }else if(base.getTop()==0){
            // 更新序号为最大
            sceneMapper.updateSort(base.getId());
        }
        if(oldInfo.getTop()==0&&base.getTop()==1){
            Integer top = Integer.MAX_VALUE;
            List<Scene> scenes = sceneMapper.findBySort(top);
            if(CollectionUtils.isNotEmpty(scenes)){
                scenes.forEach(scene -> {
                    sceneMapper.unTop(scene.getId());
                });
            }
            sceneMapper.top(base.getId(), top);
        }
    }

    @Override
    public ScenePage<SceneVO> list(SceneQueryModel model) {
        List<SceneCatalog> all = new ArrayList<>();
        if(StringUtils.isNotBlank(model.getCatalogId())){
            SceneCatalog sceneCatalog = sceneCatalogMapper.findById(model.getCatalogId());
            List<SceneCatalog> subCatalogs = sceneCatalogMapper.findNext(sceneCatalog.getId());
            for (SceneCatalog catalog : subCatalogs) {
                all.addAll(sceneCatalogMapper.findNext(catalog.getId()));
            }
            all.add(sceneCatalog);
            all.addAll(subCatalogs);
        }
        if (StringUtils.isNotEmpty(model.getStart())) {
            model.setStart(model.getStart() + " 00:00:00");
        }
        if (StringUtils.isNotEmpty(model.getEnd())) {
            model.setEnd(model.getEnd() + " 23:59:59");
        }
        User user = TagSecurityHelper.currentUser();
        Page page = PageHelper.startPage(model.getPageNumber(), model.getPageSize());
        List<SceneVO> list = sceneMapper.findList(all,model.getName(), model.getStart(), model.getEnd(),model.getType(),user.getUserId());
        return new ScenePage<SceneVO>().setContent(list).setTotalPages(page.getPages()).setRequestPager(model.getPageNumber())
                .setSize(model.getPageSize()).setTotalElements(page.getTotal());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void del(String id) {
        sceneMapper.deleteById(id);
        sceneMapper.deleteStepsBySceneId(id);
    }

    @Override
    public int countByName(String name) {
        return sceneMapper.countByName(name);
    }

    @Override
    public SceneDetailVO getDetail(String id) {
        SceneVO sceneVO=sceneMapper.findById(id);
        if(sceneVO==null){
            return null;
        }
        List<SceneStepVO> steps = sceneMapper.findStepsBySceneId(id);
        /*if(CollectionUtils.isNotEmpty(steps)){
            steps.stream().filter(step->step.getDetail()!=null).forEach(step->{
                step.setDetail(HtmlUtils.htmlUnescape(step.getDetail()));
            });
        }*/
        return new SceneDetailVO().setBase(sceneVO).setSteps(steps);
    }

    @Override
    public int countByNameAndNotId(String name, String id) {
        return sceneMapper.countByNameAndNotId(name, id);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SceneDto<Object> top(String id) {
        SceneVO base = sceneMapper.findById(id);
        if(base==null){
            log.info("场景不存在 {}",id);
            return SceneDto.error("场景不存在!");
        }
        if(base.getTop()==1){
            log.info("场景不能重复置顶 {}",id);
            return SceneDto.error("场景不能重复置顶!");
        }
        Integer top = Integer.MAX_VALUE;
        List<Scene> scenes = sceneMapper.findBySort(top);
        if(CollectionUtils.isNotEmpty(scenes)){
            scenes.forEach(scene -> {
                sceneMapper.unTop(scene.getId());
            });
        }
        sceneMapper.top(id, top);
        return SceneDto.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SceneDto<Object> down(String id) {
        Scene base = sceneMapper.findOneScene(id);
        if(base==null){
            log.info("场景不存在 {}",id);
            return SceneDto.error("场景不存在!");
        }
        if(base.getTop()==1){
            log.info("置顶不能下移 {}",id);
            return SceneDto.error("置顶不能下移!");
        }
        return topInAll(base, sceneMapper.findDownMate(base.getSort()));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SceneDto<Object> up(String id) {
        Scene base = sceneMapper.findOneScene(id);
        if(base==null){
            log.info("场景不存在 {}",id);
            return SceneDto.error("场景不存在!");
        }
        if(base.getTop()==1){
            log.info("置顶不能上移 {}",id);
            return SceneDto.error("置顶不能上移!");
        }
        return topInAll(base, sceneMapper.findUpMate(base.getSort()));
    }

    @Override
    public List<FreeTagVO> findFrees() {
        User user = TagSecurityHelper.currentUser();
        return sceneMapper.findFrees(user.getUserId());
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SceneDto<Object> up(SceneMoveModel model) {
        Scene base = sceneMapper.findOneScene(model.getId());
        if(base==null){
            log.info("场景不存在 {}",model.getId());
            return SceneDto.error("场景不存在!");
        }
        if(base.getTop()==1){
            log.info("置顶不能上移 {}",model.getId());
            return SceneDto.error("置顶不能上移!");
        }
        if(check(model)){
            // 全部数据
            return topInAll(base, sceneMapper.findUpMate(base.getSort()));
        }
        // 部分数据
        List<SceneCatalog> all = new ArrayList<>();
        if(StringUtils.isNotBlank(model.getCatalogId())){
            SceneCatalog sceneCatalog = sceneCatalogMapper.findById(model.getCatalogId());
            List<SceneCatalog> subCatalogs = sceneCatalogMapper.findNext(sceneCatalog.getId());
            for (SceneCatalog catalog : subCatalogs) {
                all.addAll(sceneCatalogMapper.findNext(catalog.getId()));
            }
            all.add(sceneCatalog);
            all.addAll(subCatalogs);
        }
        if (StringUtils.isNotEmpty(model.getStart())) {
            model.setStart(model.getStart() + " 00:00:00");
        }
        if (StringUtils.isNotEmpty(model.getEnd())) {
            model.setEnd(model.getEnd() + " 23:59:59");
        }
        Scene upMate = sceneMapper.findUpMate2(base.getSort(), all,model.getName(), model.getStart(), model.getEnd());
        if (upMate == null) {
            return SceneDto.success();
        }
        Integer upMateSort = upMate.getSort();
        sceneMapper.move(-1, base.getSort(), upMate.getSort()+1);
        sceneMapper.updateById(base.setSort(upMateSort).setUpdateTime(new Date()));
        return SceneDto.success();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public SceneDto<Object> down(SceneMoveModel model) {
        Scene base = sceneMapper.findOneScene(model.getId());
        if(base==null){
            log.info("场景不存在 {}",model.getId());
            return SceneDto.error("场景不存在!");
        }
        if(base.getTop()==1){
            log.info("置顶不能下移 {}",model.getId());
            return SceneDto.error("置顶不能下移!");
        }
        if(check(model)){
            // 全部数据
            return topInAll(base, sceneMapper.findDownMate(base.getSort()));
        }
        // 部分数据
        List<SceneCatalog> all = new ArrayList<>();
        if(StringUtils.isNotBlank(model.getCatalogId())){
            SceneCatalog sceneCatalog = sceneCatalogMapper.findById(model.getCatalogId());
            List<SceneCatalog> subCatalogs = sceneCatalogMapper.findNext(sceneCatalog.getId());
            for (SceneCatalog catalog : subCatalogs) {
                all.addAll(sceneCatalogMapper.findNext(catalog.getId()));
            }
            all.add(sceneCatalog);
            all.addAll(subCatalogs);
        }
        if (StringUtils.isNotEmpty(model.getStart())) {
            model.setStart(model.getStart() + " 00:00:00");
        }
        if (StringUtils.isNotEmpty(model.getEnd())) {
            model.setEnd(model.getEnd() + " 23:59:59");
        }
        Scene downMate = sceneMapper.findDownMate2(base.getSort(), all,model.getName(), model.getStart(),
                model.getEnd());
        if (downMate == null) {
            return SceneDto.success();
        }
        Integer downMateSort = downMate.getSort();
        sceneMapper.move(1, downMate.getSort()-1, base.getSort());
        sceneMapper.updateById(base.setSort(downMateSort).setUpdateTime(new Date()));
        return SceneDto.success();
    }

    private SceneDto<Object> topInAll(Scene base, Scene upMate) {
        if (upMate == null) {
            return SceneDto.success();
        }
        Integer upMateSort = upMate.getSort();
        sceneMapper.updateById(upMate.setSort(base.getSort()).setUpdateTime(new Date()));
        sceneMapper.updateById(base.setSort(upMateSort).setUpdateTime(new Date()));
        return SceneDto.success();
    }

    private boolean check(SceneMoveModel model) {
        if(StringUtils.isBlank(model.getName())
        &&StringUtils.isBlank(model.getStart())
        &&StringUtils.isBlank(model.getEnd())
        &&StringUtils.isBlank(model.getCatalogId())){
            return true;
        }
        return false;
    }
}
